package com.sz.admin.dtuinfo.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.mybatisflex.core.table.TableDef;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.sz.admin.system.service.SysUserService;
import com.sz.admin.vehicleinfo.pojo.po.VehicleInfo;
import com.sz.admin.vehicleinfo.pojo.vo.VehicleInfoVO;
import com.sz.core.common.entity.LoginUser;
import com.sz.core.common.exception.common.BusinessException;
import com.sz.core.datascope.SimpleDataScopeHelper;
import com.sz.mysql.SimplePermissionDialect;
import com.sz.security.core.util.LoginUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.sz.admin.dtuinfo.service.DtuInfoService;
import com.sz.admin.dtuinfo.pojo.po.DtuInfo;
import com.sz.admin.dtuinfo.mapper.DtuInfoMapper;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.query.QueryChain;
import com.sz.core.common.enums.CommonResponseEnum;
import com.sz.core.util.PageUtils;
import com.sz.core.util.BeanCopyUtils;
import com.sz.core.util.Utils;
import com.sz.core.common.entity.PageResult;
import com.sz.core.common.entity.SelectIdsDTO;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.Objects;
import java.util.stream.Collectors;
import com.sz.admin.dtuinfo.pojo.dto.DtuInfoCreateDTO;
import com.sz.admin.dtuinfo.pojo.dto.DtuInfoUpdateDTO;
import com.sz.admin.dtuinfo.pojo.dto.DtuInfoListDTO;
import com.sz.admin.dtuinfo.pojo.dto.DtuInfoImportDTO;
import com.sz.core.common.entity.ImportExcelDTO;
import com.sz.excel.core.ExcelResult;
import java.io.OutputStream;
import jakarta.servlet.http.HttpServletResponse;
import com.sz.core.util.FileUtils;
import com.sz.excel.utils.ExcelUtils;
import lombok.SneakyThrows;
import com.sz.admin.dtuinfo.pojo.vo.DtuInfoVO;
import com.sz.admin.system.mapper.SysUserDeptMapper;
import com.sz.admin.system.mapper.SysDeptMapper;
import com.sz.admin.system.pojo.po.SysDept;
//import static com.sz.admin.system.pojo.po.table.SysUserTableDef.SYS_USER;
import static com.sz.admin.dtuinfo.pojo.po.table.DtuInfoTableDef.DTU_INFO;
import static com.sz.admin.system.pojo.po.table.SysDeptTableDef.SYS_DEPT;
import static com.sz.admin.system.pojo.po.table.SysUserDeptTableDef.SYS_USER_DEPT;
import static com.sz.admin.vehicleinfo.pojo.po.table.VehicleInfoTableDef.VEHICLE_INFO;

import com.sz.core.util.RandomPwd;
/**
 * <p>
 * DTU信息表 服务实现类
 * </p>
 *
 * @author sz-admin
 * @since 2025-08-29
 */
@Service
@RequiredArgsConstructor
public class DtuInfoServiceImpl extends ServiceImpl<DtuInfoMapper, DtuInfo> implements DtuInfoService {
    private final DtuInfoMapper dtuInfoMapper;
    private final SysUserService sysUserService;
    private final SysUserDeptMapper sysUserDeptMapper;
    private final SysDeptMapper sysDeptMapper;

    @Override
    public void create(DtuInfoCreateDTO dto){
        // Trim spaces from dtuNumber to prevent storing spaces
        if (dto.getDtuNumber() != null) {
            dto.setDtuNumber(dto.getDtuNumber().trim());
        }
        
        DtuInfo dtuInfo = BeanCopyUtils.copy(dto, DtuInfo.class);
        // 检查车辆编号是否已存在（未删除的）
        QueryWrapper queryWrapper = QueryWrapper.create()
                .select()
                .where(DTU_INFO.DTU_NUMBER.eq(dtuInfo.getDtuNumber()));

        List<DtuInfo> dtuInfoList = dtuInfoMapper.selectListByQuery(queryWrapper);
        // 判断查询结果是否不为空
        boolean exists = dtuInfoMapper.selectCountByQuery(queryWrapper) > 0;

        if (exists) {
            // 使用 BusinessException 抛出业务异常
            throw new BusinessException(
                    CommonResponseEnum.EXISTS, // 传递一个有效的响应枚举
                    new Object[]{dtuInfo.getDtuNumber()}, // 参数
                    "DTU编号 " + dtuInfo.getDtuNumber() + " 已存在" // 消息
            );
        }
        // 调用随机密码生成方法
        String password = RandomPwd.getRandomPwd(10);
        dtuInfo.setBindToken(password);
        save(dtuInfo);
    }

    @Override
    public void update(DtuInfoUpdateDTO dto){
        // Trim spaces from dtuNumber to prevent storing spaces
        if (dto.getDtuNumber() != null) {
            dto.setDtuNumber(dto.getDtuNumber().trim());
        }
        
        DtuInfo dtuInfo = BeanCopyUtils.copy(dto, DtuInfo.class);
        QueryWrapper wrapper;
        // id有效性校验
        wrapper = QueryWrapper.create()
            .eq(DtuInfo::getId, dto.getId());
        CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0);

        saveOrUpdate(dtuInfo);
    }

    @Override
    public PageResult<DtuInfoVO> page(DtuInfoListDTO dto){
//        try {
//            SimpleDataScopeHelper.start(DtuInfo.class); // 指定要追加条件的表PO实体
            QueryWrapper wrapper = buildQueryWrapper(dto);
            // 定义表别名
            //TableDef dept = SYS_DEPT.as("dept");
//        Object loginId = StpUtil.getTokenSession().getLoginId();
//        Long loginIds = (Long) loginId;
        Long userId = StpUtil.getLoginIdAsLong(); // 转换为Long类型
        //LoginUser loginUser = sysUserService.buildLoginUser(userId);

            //LoginUser loginUser = getLoginUser();
            //Long userId = loginUser.getUserInfo().getId();
            //List<Long> deptIds =loginUser.getDeptAndChildren();
        LoginUser loginUser = LoginUtils.getLoginUser();
        assert loginUser != null;
        // 获取用户直接关联的部门ID
        List<Long> directDeptIds = loginUser.getDepts();
        
        // 递归查询这些部门及其所有子部门（基于PID关系）
        Set<Long> deptAndChildren = new HashSet<>();
        if (directDeptIds != null && !directDeptIds.isEmpty()) {
            deptAndChildren.addAll(directDeptIds);
            findChildDepartments(directDeptIds, deptAndChildren);
        }

            // 添加关联查询 - 使用方法引用
            wrapper.select(DTU_INFO.ALL_COLUMNS) // 使用方法引用并设置别名
                    .select(VEHICLE_INFO.VEHICLE_NUMBER.as("vehicleNumber"), VEHICLE_INFO.TITLE.as("vehicleTitle"))
                    .select(SYS_DEPT.ID.as("deptID"), SYS_DEPT.NAME.as("deptName"))
                    .leftJoin(VEHICLE_INFO).on(VEHICLE_INFO.ID.eq(DTU_INFO.VEHICLE_ID))
                    .leftJoin(SYS_DEPT).on(SYS_DEPT.ID.eq(VEHICLE_INFO.DEPARTMENT_ID))
                    //.where(VEHICLE_INFO.DEPARTMENT_ID.in(deptIds))
            ;
            // 根据用户角色动态添加条件
            System.out.println("DTU查询 - 用户ID: " + userId + ", 用户名: " + loginUser.getUserInfo().getUsername());
            System.out.println("DTU查询 - 部门ID列表: " + (deptAndChildren != null ? deptAndChildren : "null"));
            
            if(userId != 1) {
                // 非超级管理员，需要添加部门过滤条件
                if (deptAndChildren != null && !deptAndChildren.isEmpty()) {
                    // 只查询所属部门及下级部门的设备
                    wrapper.where(VEHICLE_INFO.DEPARTMENT_ID.in(new ArrayList<>(deptAndChildren)));
                } else {
                    // 部门列表为空，尝试获取用户直接部门ID
                    List<Long> directDeptIdsForFallback = loginUser.getDepts();
                    System.out.println("DTU查询 - 直接部门ID列表: " + (directDeptIdsForFallback != null ? directDeptIdsForFallback : "null"));
                    
                    if (directDeptIdsForFallback != null && !directDeptIdsForFallback.isEmpty()) {
                        // 使用直接部门ID过滤
                        wrapper.where(VEHICLE_INFO.DEPARTMENT_ID.in(directDeptIdsForFallback));
                    } else {
                        System.out.println("警告: 用户" + userId + "没有任何部门权限，不查询任何设备");
                        // 添加一个永远不满足的条件，确保不查询任何设备
                        wrapper.where("1 = 0");
                    }
                }
            }
            // 超级管理员跳过部门过滤，查询所有设备
            System.out.println("Generated SQL: " + wrapper.toSQL());
            Page<DtuInfoVO> page = pageAs(PageUtils.getPage(dto), wrapper, DtuInfoVO.class);

            return PageUtils.getPageResult(page);
//        } finally {
//            SimpleDataScopeHelper.clearDataScope();
//        }
    }

    @Override
    public List<DtuInfoVO> list(DtuInfoListDTO dto){
        return listAs(buildQueryWrapper(dto), DtuInfoVO.class);
    }

    @Override
    public void remove(SelectIdsDTO dto){
        CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty());
        removeByIds(dto.getIds());
    }

    @Override
    public DtuInfoVO detail(Object id){
        DtuInfo dtuInfo = getById((Serializable) id);
        CommonResponseEnum.INVALID_ID.assertNull(dtuInfo);
        return BeanCopyUtils.copy(dtuInfo, DtuInfoVO.class);
    }

    @SneakyThrows
    @Override
    public void importExcel(ImportExcelDTO dto) {
        ExcelResult<DtuInfoImportDTO> excelResult = ExcelUtils.importExcel(dto.getFile().getInputStream(), DtuInfoImportDTO.class, true);
        List<DtuInfoImportDTO> list = excelResult.getList();
        
        // Trim spaces from dtuNumber in imported data
        for (DtuInfoImportDTO importDTO : list) {
            if (importDTO.getDtuNumber() != null) {
                importDTO.setDtuNumber(importDTO.getDtuNumber().trim());
            }
        }
        
        List<String> errorList = excelResult.getErrorList();
        String analysis = excelResult.getAnalysis();
        System.out.println(" analysis : " + analysis);
        System.out.println(" isCover : " + dto.getIsCover());
    }

    @SneakyThrows
    @Override
    public void exportExcel(DtuInfoListDTO dto, HttpServletResponse response) {
        List<DtuInfoVO> list = list(dto);
        String fileName = "DTU信息表模板";
        OutputStream os = FileUtils.getOutputStream(response, fileName + ".xlsx");
        ExcelUtils.exportExcel(list, "DTU信息表", DtuInfoVO.class, os);
    }

    private static QueryWrapper buildQueryWrapper(DtuInfoListDTO dto) {
        QueryWrapper wrapper = QueryWrapper.create().from(DtuInfo.class);
        if (Utils.isNotNull(dto.getDtuNumber())) {
            wrapper.eq(DtuInfo::getDtuNumber, dto.getDtuNumber());
        }
        if (Utils.isNotNull(dto.getName())) {
            wrapper.like(DtuInfo::getName, dto.getName());
        }
        if (Utils.isNotNull(dto.getSort())) {
            wrapper.eq(DtuInfo::getSort, dto.getSort());
        }
        if (Utils.isNotNull(dto.getIccid())) {
            wrapper.eq(DtuInfo::getIccid, dto.getIccid());
        }
        if (Utils.isNotNull(dto.getLedid())) {
            wrapper.eq(DtuInfo::getLedid, dto.getLedid());
        }
        if (Utils.isNotNull(dto.getBindToken())) {
            wrapper.eq(DtuInfo::getBindToken, dto.getBindToken());
        }
        if (Utils.isNotNull(dto.getDtuStatus())) {
            wrapper.eq(DtuInfo::getDtuStatus, dto.getDtuStatus());
        }
        if (Utils.isNotNull(dto.getBindTimeStart()) && Utils.isNotNull(dto.getBindTimeEnd())) {
            wrapper.between(DtuInfo::getBindTime, dto.getBindTimeStart(), dto.getBindTimeEnd());
        }
        if (Utils.isNotNull(dto.getExpireTimeStart()) && Utils.isNotNull(dto.getExpireTimeEnd())) {
            wrapper.between(DtuInfo::getExpireTime, dto.getExpireTimeStart(), dto.getExpireTimeEnd());
        }
        if (Utils.isNotNull(dto.getVehicleId())) {
            wrapper.eq(DtuInfo::getVehicleId, dto.getVehicleId());
        }
        return wrapper;
    }
    
    /**
     * 递归查找子部门
     * 
     * @param parentDeptIds 父部门ID列表
     * @param result 结果集合
     */
    private void findChildDepartments(List<Long> parentDeptIds, Set<Long> result) {
        if (parentDeptIds.isEmpty()) {
            return;
        }
        
        // 查询父部门的直接子部门
        QueryWrapper childQuery = QueryWrapper.create()
                .select(SYS_DEPT.ID)
                .from(SYS_DEPT)
                .where(SYS_DEPT.PID.in(parentDeptIds))
                .and(SYS_DEPT.DEL_FLAG.eq("F"));
        
        List<SysDept> childDepts = sysDeptMapper.selectListByQuery(childQuery);
        if (childDepts.isEmpty()) {
            return;
        }
        
        // 提取子部门ID
        List<Long> childDeptIds = childDepts.stream()
                .map(SysDept::getId)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        
        // 添加到结果中
        result.addAll(childDeptIds);
        
        // 递归查找子部门的子部门
        findChildDepartments(childDeptIds, result);
    }
}